/*  _________________________________________
   /                                      /_ \
  |  			User Input               |/ \ |
  |                                      |___||
   \______________________________________\_/ |
       |                                      |
      /     User Input Receiver              /
     /     Written April, 2009,             /
    |     by Darrell Eastman.              |___
    |                                      |   |
     \______________________________________\_/
*/

/*
To receive events like mouse and keyboard input, or GUI events like "the OK
button has been clicked", we need an object which is derived from the
IEventReceiver object. There is only one method to override:
IEventReceiver::OnEvent(). This method will be called by the engine once
when an event happens. What we really want to know is whether a key is being
held down, and so we will remember the current state of each key.
*/

#include <irrlicht.h>
#include "usermovement.h"

using namespace irr;
using namespace core;

//Action Key Map
struct KeyMap
{
	//Up
	SKeyMap			KeyUp;
	KeyUp.Action		= EKA_KEY_UP;
	KeyUp.KeyCode		= null;
	//Down
	SKeyMap			KeyDown;
	KeyDown.Action		= EKA_KEY_DOWN;
	KeyDown.KeyCode	= null;
	//Left
	SKeyMap			KeyLeft;
	KeyLeft.Action		= EKA_KEY_LEFT;
	KeyLeft.KeyCode	= null;
	//Right
	SKeyMap			KeyRight;
	KeyRight.Action	= EKA_KEY_RIGHT;
	KeyRight.KeyCode	= null;
	//Sprint
	SKeyMap			KeySprint;
	KeySprint.Action	= EKA_KEY_SPRINT;
	KeySprint.KeyCode	= null;
	//Jump
	SKeyMap			KeyJump;
	KeyJump.Action		= EKA_KEY_JUMP;
	KeyJump.KeyCode	= null;
	//Crouch
	SKeyMap			KeyCrouch;
	KeyCrouch.Action	= EKA_KEY_CROUCH;
	KeyCrouch.KeyCode	= null;
	//Action Pri
	SKeyMap			KeyActPri;
	KeyActPri.Action	= EKA_KEY_ACTPRI;
	KeyActPri.KeyCode	= null;
	//Action Sec
	SKeyMap			KeyActSec;
	KeyActSec.Action	= EKA_KEY_ACTSEC;
	KeyActSec.KeyCode	= null;
	//Use
	SKeyMap			KeyUse;
	KeyUse.Action		= EKA_KEY_USE;
	KeyUse.KeyCode		= null;
}

class GamePad : public IEventReciver
{
public:
	OnEvent()
}
const int SER_MOUSE_LEFT = 0;

const int SER_MOUSE_RIGHT = 1;

const int SER_MOUSE_MIDDLE = 2;

class SmoothEventReceiver : public IEventReceiver
{
public:
	int		m_key_cnt[256];
	int		m_key_buf[256];
	int		m_key_buf_old[256];
	int		m_key_up_down[256];
	int		m_key_down_up[256];
	int		m_key_shift[256];
	int		m_key_ctrl[256];
	int		m_key_menu[256];
	
	int		m_mouse_button_cnt[3];
	int		m_mouse_button_buf[3];
	int		m_mouse_button_buf_old[3];
	int		m_mouse_button_up_down[3];
	int		m_mouse_button_down_up[3];
	int		m_mouse_button_shift[3];
	int		m_mouse_button_ctrl[3];
	int		m_mouse_button_menu[3];

	int		m_mouse_x;
	int		m_mouse_y;
	float	m_mouse_z;

	createReceiver:SmoothEventReceiver()
	{
		return SmoothEventReceiver(SmoothEventReceiver.create(SmoothEventReceiver.generate));
	}

	int	OnEvent(SEvent event)
	{
		
		int event_type = event.getEventType();
		
		if( event_type = EET_KEY_INPUT_EVENT )
		{
			int key = event.getKeyInputKey();
		
			m_key_buf_old[key] = m_key_buf[key];
			m_key_buf[key] = event.getKeyPressedDown();

			//store the modifier flags
			m_key_shift[key] = event.getKeyShift();
			m_key_ctrl[key] = event.getKeyControl();
			m_key_menu[key] = IsKeyDown(EKEY_MENU) || IsKeyDown(EKEY_LMENU) || IsKeyDown(EKEY_RMENU);
			
			//store state changes
			m_key_up_down[key] = (m_key_buf[key] && ! m_key_buf_old[key]);
			m_key_down_up[key] = (! m_key_buf[key] && m_key_buf_old[key]);

			//log a key hit if the key is down and it wasnt down before
			if( m_key_up_down[key] ) m_key_cnt[key]:+1;
		}
		else if( event_type = EET_MOUSE_INPUT_EVENT )
		{
			int eventType = event.getMouseEventType();

			if( eventType < EMIE_MOUSE_MOVED )
			{
				int button = (event.getMouseEventType() Mod 3);
				
				//store the old state
				m_mouse_button_buf_old[button] = m_mouse_button_buf[button];
				
				//set the current state
				m_mouse_button_buf[button] = ! (event.getMouseEventType()/3);

				//store state changes
				m_mouse_button_up_down[button] = (m_mouse_button_buf[button] && ! m_mouse_button_buf_old[button]);
				m_mouse_button_down_up[button] = (! m_mouse_button_buf[button] && m_mouse_button_buf_old[button]);
				
				//log a hit if the state went from up to down
				if( m_mouse_button_up_down[button] ) m_mouse_button_cnt[button]:+1;
				
				//store the modifier flags
				m_mouse_button_shift[button] = IsKeyDown(EKEY_SHIFT) || IsKeyDown(EKEY_LSHIFT) || IsKeyDown(EKEY_RSHIFT);
				m_mouse_button_ctrl[button] = IsKeyDown(EKEY_CONTROL) || IsKeyDown(EKEY_LCONTROL) || IsKeyDown(EKEY_RCONTROL);
				m_mouse_button_menu[button] = IsKeyDown(EKEY_MENU) || IsKeyDown(EKEY_LMENU) || IsKeyDown(EKEY_RMENU);
			}
			else if( eventType = EMIE_MOUSE_MOVED )
			{
				m_mouse_x = event.getMouseX();
				m_mouse_y = event.getMouseY();
			}
			else if( eventType = EMIE_MOUSE_WHEEL )
			{
				m_mouse_z = event.getMouseWheel();
			}
		}
		
		return Super.OnEvent(event);
	}

	generate:IEventReceiver()
	{
		return new SmoothEventReceiver;
	}

	// ------------------------------------------------
	// keyboard functions
	// ------------------------------------------------
		

	int KeyHitCnt(int index, int bClear = false)
	{
		int retval = m_key_cnt[index];
		if( bClear ) m_key_cnt[index] = 0;
		return retval;
	}
	
	int IsKeyDown(int index, int bCheckShift = false, int bCheckCtrl = false, int bCheckMenu = false) 
	{
		// check the key itself
		int bKeyDown = m_key_buf[index];
		// check the shift modifier
		bKeyDown = bKeyDown && (! bCheckShift || m_key_shift[index]);
		// check the control modifier
		bKeyDown = bKeyDown && (! bCheckCtrl || m_key_ctrl[index]);
		// check the menu  modifier
		bKeyDown = bKeyDown && (! bCheckMenu || m_key_menu[index]);
		
		return bKeyDown;
	}
	
	int IsKeyUpDown(int index, int bClear = true)
	{
		int bIsKeyUpDown = m_key_up_down[index];
		if( bClear ) m_key_up_down[index] = false;
		return bIsKeyUpDown;
	}
	
	int IsKeyDownUp(int index, int bClear = true)
	{
		int bIsKeyDownUp = m_key_down_up[index];
		if( bClear ) m_key_down_up[index] = false;
		return bIsKeyDownUp;
	}

	FlushKeys()
	{
		m_key_cnt = new int[256];
		m_key_buf = new int[256];
		m_key_buf_old = new int[256];
		m_key_up_down = new int[256];
		m_key_down_up = new int[256];
		m_key_shift = new int[256];
		m_key_ctrl = new int[256];
		m_key_menu = new int[256];
	}

	//------------------------------------------------
	//mouse functions
	//------------------------------------------------

	int MouseHitCnt(int index, int bClear = false)
	{
		int retval = m_mouse_button_cnt[index];
		if( bClear ) m_mouse_button_cnt[index] = 0;
		return retval;
	}
	
	int IsMouseButtonDown(int index, int bCheckShift = false, int bCheckCtrl = false, int bCheckMenu = false)
	{
		//check the key itself
		int bButtonDown = m_mouse_button_buf[index];
		//check the shift modifier
		bButtonDown = bButtonDown && ( ! bCheckShift || m_mouse_button_shift[index]);
		//check the control modifier
		bButtonDown =  bButtonDown && ( ! bCheckCtrl || m_mouse_button_ctrl[index]);
		//check the menu  modifier
		bButtonDown = bButtonDown && ( ! bCheckMenu || m_mouse_button_menu[index]);
		
		return bButtonDown;
	}
	
	int IsMouseButtonUpDown(int index, int bClear = true)
	{
		int bIsMouseUpDown = m_mouse_button_up_down[index];
		if( bClear ) m_mouse_button_up_down[index] = false;
		return bIsMouseUpDown;
	}
	
	int IsMouseButtonDownUp(int index, int bClear = true)
	{
		int bIsMouseDownUp = m_mouse_button_down_up[index]
		if( bClear ) m_mouse_button_down_up[index] = false
		return bIsMouseDownUp;
	}
	
	int MouseX()
	{
		return m_mouse_x;
	}

	int MouseY()
	{
		return m_mouse_y;
	}

	float MouseZ()
	{
		return m_mouse_z;
	}

	FlushMouse()
	{
		m_mouse_button_cnt		= new int[3];
		m_mouse_button_buf		= new int[3];
		m_mouse_button_buf_old	= new int[3];
		m_mouse_button_up_down	= new int[3];
		m_mouse_button_down_up	= new int[3];
		m_mouse_button_shift		= new int[3];
		m_mouse_button_ctrl		= new int[3];
		m_mouse_button_menu		= new int[3];
	}

	// -------------------------------------------
	//|            JoyStick Functions             |
	// -------------------------------------------
	

};

class MyEventReceiver : public IEventReceiver
{
public:					//We'll create a struct to record	  
						//	 info on the mouse state		  
	struct SMouseState
	{
		position2di	Position;
		bool			LeftButtonDown;
		SMouseState():LeftButtonDown( false )
		{
		}
	}	MouseState;

	// This is the one method that we have to implement
	virtual	bool	OnEvent( const	SEvent & event )
	{
		//Up or Down Key
		if( event.EventType == EET_KEY_INPUT_EVENT )
			KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;

		//Remember the mouse state
		if( event.EventType == EET_MOUSE_INPUT_EVENT )
		{
			switch( event.MouseInput.Event )
			{
			case EMIE_LMOUSE_PRESSED_DOWN:
				MouseState.LeftButtonDown = true;
				break;
			case EMIE_LMOUSE_LEFT_UP:
				MouseState.LeftButtonDown = false;
				break;
			case EMIE_MOUSE_MOVED:
				MouseState.Position.X = event.MouseInput.X;
				MouseState.Position.Y = event.MouseInput.Y;
				break;
			default:	//We won't use the wheel  	  
				break;
			}
		}
		if( event.EventType == EET_GUI_EVENT )
		{
			s32					id	= event.GUIEvent.Caller->getID();
			IGUIEnvironment*	env	= Context.device->getGUIEnvironment();

			switch( event.GUIEvent.EventType )
			{

			/*
			If a scrollbar changed its scroll position, and it is
			'our' scrollbar (the one with id GUI_ID_TRANSPARENCY_SCROLL_BAR), then we change
			the transparency of all gui elements. This is a very
			easy task: There is a skin object, in which all color
			settings are stored. We simply go through all colors
			stored in the skin and change their alpha value.
			*/
			case EGET_SCROLL_BAR_CHANGED:
				if( id == GUI_ID_TRANSPARENCY_SCROLL_BAR )
				{
					s32 pos = (( IGUIScrollBar* )event.GUIEvent.Caller )->getPos();
					
					for( u32 i = 0; i < EGDC_COUNT; ++i )
					{
						SColor col = env->getSkin()->getColor(( EGUI_DEFAULT_COLOR )i );
						col.setAlpha( pos );
						env->getSkin()->setColor(( EGUI_DEFAULT_COLOR)i, col );
					}
					
				}
				break;

			/*
			If a button was clicked, it could be one of 'our'
			three buttons. If it is the first, we shut down the engine.
			If it is the second, we create a little window with some
			text on it. We also add a string to the list box to log
			what happened. && if it is the third button, we create
			a file open dialog, and add also this as string to the list box.
			That's all for the event receiver.
			*/
			case EGET_BUTTON_CLICKED:
				switch( id )
				{
				case GUI_ID_QUIT_BUTTON:
					Context.device->closeDevice();
					return true;

				case GUI_ID_NEW_WINDOW_BUTTON:
					{
					Context.listbox->addItem( L"Window created" );
					Context.counter += 30;
					if( Context.counter > 200 )
						Context.counter = 0;

					IGUIWindow* window = env->addWindow(
						rect<s32>( 100 + Context.counter, 100 + Context.counter, 300 + Context.counter, 200 + Context.counter ),
						false, // modal?
						L"Test window" );

					env->addStaticText(L"Please close me",
						rect<s32>(35,35,140,50),
						true, // border?
						false, // wordwrap?
						window);
					}
					return true;

				case GUI_ID_FILE_OPEN_BUTTON:
					Context.listbox->addItem( L"File open" );
					env->addFileOpenDialog( L"Please choose a file." );
					return true;

				default:
					return false;
				}
				break;

			default:
				break;
			}
		}

		return false;

		// The state of each connected joystick is sent to us
		// once every run() of the Irrlicht device.  Store the
		// state of the first joystick, ignoring other joysticks.
		// This is currently only supported on Windows and Linux.
		if( event.EventType == EET_JOYSTICK_INPUT_EVENT
			&& event.JoystickEvent.Joystick == 0 )
		{
			JoystickState = event.JoystickEvent;
		}

		return false;
	}

	// This is used to check whether a key is being held down
	virtual	bool	IsKeyDown( EKEY_CODE keyCode )const
	{
		return KeyIsDown[keyCode];
	}

	virtual	bool	IsKeyUpDown( EKEY_CODE keyCode )const
	{
		return keyIsDown[keyCode];
	}
	const		SEvent::SJoystickEvent	&GetJoystickState( void )const
	{
		return JoystickState;
	}

	const		SMouseState	&GetMouseState( void )const
	{
		return MouseState;
	}

	MyEventReceiver()
	{
		for( u32 i = 0; i<KEY_KEY_CODES_COUNT; ++i )
		KeyIsDown[i] = false;
	}
private:
	SEvent::SJoystickEvent	JoystickState;

	// We use this array to store the current state of each key
	bool	KeyIsDown[KEY_KEY_CODES_COUNT];
};


//VOIP Chat
class arrr
{
public:
private:
};